/** uupaa-drag.js
 *
 * uupaa-drag.js is drag and drop layer support javascript library
 *  - uupaa.js spin-off project
 *
 * @author Takao Obara <uupaa.js@gmail.com>
 * @license uupaa-drag.js is licensed under the terms and conditions of the MIT licence.
 * @version 0.1
 * @date 2008-12-13
 * @see <a href="http://code.google.com/p/uupaa-js/">uupaa.js Home(Google Code)</a>
 * @see <a href="http://code.google.com/p/uupaa-js-spinoff/">uupaa.js SpinOff Project Home(Google Code)</a>
 */
if (!uuClass.SimplyDrag) {

/** Simply Drag and Drop
 *
 * @class
 */
uuClass.SimplyDrag = function(elm) {
  this.construct.call(this, elm);
};

/** z-index management
 *
 * @class
 */
uuClass.ZIndexer = function() {
  var me = this, fn = arguments.callee;
  if (!fn.instance) {
    fn.instance = me; // keep instance
    me.construct.apply(me, arguments);
  }
  return fn.instance;
};

uuConst.Event.Kind.Drag = {
  // event.type     kind
  mousedown:        0x0001,
  mouseup:          0x0002,
  mousemove:        0x0003,
  losecapture:      0x0102  // mouseup
};

// --- local scope ------------------------------------------------------
(function() {
var _doc = document, _ua = uuClass.Detect, _iebody = null,
    DRAGGING      = "_uuEventDragging",
    DRAG_OFFSET   = "_uuEventDragOffset";

// uuClass.Event.drag - generic drag and drop impl
uuClass.Event.prototype.drag = function(evt, elm) {
              var mx, my, off,
                  kind = 0xff && (uuConst.Event.Kind.Drag[evt.type] || 0),
                  cs, rx, ry, x, y;

              if (!kind || (kind > 0x3) ||
                  (kind === 0x3 && !elm[DRAGGING]) || // 0x3: mousemove
                  (kind === 0x1 &&  elm[DRAGGING]) || // 0x1: mousedown
                  (kind === 0x2 && !elm[DRAGGING])) { // 0x2: mouseup
                return 0;
              }

              if (_ua.ie) {
                if (!_iebody) { _iebody = _doc.documentElement || _doc.body; }
                mx = evt.clientX + _iebody.scrollLeft;
                my = evt.clientY + _iebody.scrollTop;
              } else {
                mx = evt.pageX;
                my = evt.pageY;
              }

              switch (kind) {
              case 3: // mousemove
                off = elm[DRAG_OFFSET];
                x = mx - off.x;
                y = my - off.y;
                if (_ua.ie) {
                  elm.style.pixelLeft = x;
                  elm.style.pixelTop  = y;
                } else {
                  elm.style.left = x + "px";
                  elm.style.top  = y + "px";
                }
                return { x: mx, y: my, kind: kind };
              case 1: // mousedown
                elm[DRAGGING] = 1;
                (new uuClass.ZIndexer()).beginDrag(elm);

                if (_ua.ie) {
                  rx = elm.offsetLeft;
                  ry = elm.offsetTop;
                } else {
                  cs = _doc.defaultView.getComputedStyle(elm, "");
                  rx = parseFloat(cs.left);
                  ry = parseFloat(cs.top);
                }
                x = mx - rx;
                y = my - ry;
                elm[DRAG_OFFSET] = { x: x, y: y };
                return { x: x, y: y, kind: kind };
              case 2: // mouseup
                elm[DRAGGING] = 0;
                (new uuClass.ZIndexer()).endDrag(elm);

                return { x: mx, y: my, kind: kind };
              }
              return 0;
};

uuClass.SimplyDrag.prototype = {
  construct:
            function(elm) {
              this.elm = elm;
              elm.style.cursor = "move";
              uu.event.attach(this.elm, "mousedown", this);
            },
  handleEvent:
            function(evt) {
              uu.event.stop(evt);
              uu.event.drag(evt, this.elm);
              if (uu.event.kind(evt) <= 2) {
                uu.event.toggle(_ua.ie ? this.elm : _doc,
                                "mousemove,mouseup", this, true);
              }
            }
};

uuClass.ZIndexer.prototype = {
  construct:
            function() {
              this._elm   = [];   // registed elelemt
              this._boost = 5000; // temporarily z-index in dragging
              this._top   = 20;   // top z-index
            },
  // uuClass.Drag.ZIndexer.set - regist
  set:      function(elm) {
              if (this._elm.indexOf(elm) !== -1) { return this; }
              this._elm.push(elm);
              elm.style.zIndex = ++this._top; // top + 1
              return this;
            },
  // uuClass.Drag.ZIndexer.unset - unregist
  unset:    function(elm) {
              if (this._elm.indexOf(elm) === -1) { return this; }
              delete this._elm[this._elm.indexOf(elm)];
              --this._top;
              return this;
            },
  // uuClass.Drag.ZIndexer.beginDrag
  beginDrag:
            function(elm) {
              if (this._elm.indexOf(elm) === -1) {
                this.set(elm); // auto regist
              } else {
              }
              this._sink(elm);
              elm.style.zIndex = this._boost + 1;
              return this;
            },
  // uuClass.Drag.ZIndexer.endDrag
  endDrag:  function(elm) {
              if (this._elm.indexOf(elm) === -1) { return this; }
              elm.style.zIndex = this._top; // move surface
              return this;
            },
  // uuClass.Drag.ZIndexer.top
  top:      function(elm) {
              if (this._elm.indexOf(elm) === -1) { return this; }
              this._sink(elm);
              elm.style.zIndex = this._top; // move surface
              return this;
            },
  _sink:    function(elm) {
              var thresh = elm.style.zIndex || 10; // threshold
              this._elm.forEach(function(v) {
                (v.style.zIndex > thresh) && (v.style.zIndex -= 1);
              });
            }
};

})(); // end (function())() scope

} // if (!uuClass.SimplyDrag)

